package com.suieqian.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.base.Preconditions;
import com.suieqian.config.Env;
import com.suieqian.dto.req.RoleMenuTreeReq;
import com.suieqian.dto.req.SysMenuReq;
import com.suieqian.dto.resp.HomeMenuTreeResp;
import com.suieqian.dto.resp.SysMenuResp;
import com.suieqian.entity.RoleMenuRef;
import com.suieqian.entity.User;
import com.suieqian.entity.UserRoleRef;
import com.suieqian.enums.DelStatusEnum;
import com.suieqian.enums.MenuIdEnum;
import com.suieqian.service.IRoleMenuRefService;
import com.suieqian.service.ISysMenuService;
import com.suieqian.service.IUserRoleRefService;
import com.suieqian.service.IUserService;
import com.suieqian.util.Message;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单管理
 *
 * @author lirch
 */
@Api(tags = "菜单管理")
@RestController
@RequestMapping("api/menuController")
@Slf4j
public class MenuController {

    @Resource
    private ISysMenuService sysMenuService;

    @Resource
    private IRoleMenuRefService roleMenuRefService;

    @Resource
    private IUserRoleRefService userRoleRefService;

    @Resource
    private IUserService userService;

    @ApiOperation("首页菜单tree")
    @GetMapping(value = "/listMenuTree")
    public Message<List<HomeMenuTreeResp>> listMenuTree() {
        try {
            User user = Env.getUser();

            LambdaQueryWrapper<UserRoleRef> userRoleRefLqw = Wrappers.lambdaQuery();
            userRoleRefLqw.eq(UserRoleRef::getUserId, user.getUserId());
            List<UserRoleRef> userRoleRefList = userRoleRefService.list(userRoleRefLqw);
            if (CollUtil.isEmpty(userRoleRefList)) {
                return Message.success(null);
            }
            LambdaQueryWrapper<RoleMenuRef> roleMenuRefLqw = Wrappers.lambdaQuery();
            roleMenuRefLqw.eq(RoleMenuRef::getDelStatus, DelStatusEnum.NORMAL.getCode())
                    .in(RoleMenuRef::getRoleId, userRoleRefList.stream().map(item -> item.getRoleId()).collect(Collectors.toSet()));
            List<RoleMenuRef> roleMenuRefList = roleMenuRefService.list(roleMenuRefLqw);
            if (CollUtil.isEmpty(roleMenuRefList)) {
                return Message.success(null);
            }
            List<Long> menuIds = roleMenuRefList.stream().map(item -> item.getMenuId()).collect(Collectors.toSet()).stream().collect(Collectors.toList());
            List<SysMenuResp> menus = sysMenuService.getMenus(menuIds, null);
            List<HomeMenuTreeResp> homeMenuTreeRespList = buildMenuTree(menus, null);
            return Message.success(homeMenuTreeRespList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("首页菜单获取失败");
        }
    }

    @ApiOperation("加载子类菜单")
    @GetMapping(value = "/listMenuByParentId")
    public Message<List<SysMenuResp>> listMenuByParentId(Long pid) {
        Preconditions.checkArgument(Objects.nonNull(pid), "菜单id不能为空");
        try {
            List<SysMenuResp> menus = sysMenuService.listMenuByPid(pid);
            return Message.success(menus);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("子类菜单获取失败");
        }
    }

    @PostMapping("/addMenu")
    @ApiOperation("创建菜单")
    public Message<Long> addMenu(SysMenuReq reqVO) {
        Preconditions.checkArgument(StrUtil.isNotBlank(reqVO.getName()), "菜单名称不能为空");
        try {
            Long menuId = sysMenuService.createMenu(reqVO);
            return Message.success(menuId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("创建菜单失败");
        }

    }

    @PostMapping("/modMenu")
    @ApiOperation("修改菜单")
    public Message<Boolean> modMenu(SysMenuReq reqVO) {
        Preconditions.checkArgument(Objects.nonNull(reqVO.getId()), "菜单id不能为空");
        Preconditions.checkArgument(StrUtil.isNotBlank(reqVO.getName()), "菜单名称不能为空");
        try {
            sysMenuService.updateMenu(reqVO);
            return Message.success(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("修改菜单失败");
        }
    }

    @PostMapping("/delete")
    @ApiOperation("删除菜单")
    public Message<Boolean> delete(Long id) {
        Preconditions.checkArgument(Objects.nonNull(id), "菜单id不能为空");
        try {
            sysMenuService.deleteMenu(id);
            return Message.success(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("删除菜单失败");
        }
    }

    @ApiOperation("角色管理-菜单tree")
    @GetMapping(value = "/listMenuTreeByRoleId")
    public Message<List<HomeMenuTreeResp>> listMenuTreeByRoleId(Long roleId) {
        Preconditions.checkArgument(Objects.nonNull(roleId), "角色id不能为空");
        try {
            List<SysMenuResp> menus = sysMenuService.getMenus(null, null);

            LambdaQueryWrapper<RoleMenuRef> lqw = Wrappers.lambdaQuery();
            lqw.eq(RoleMenuRef::getDelStatus, DelStatusEnum.NORMAL.getCode())
                    .eq(RoleMenuRef::getRoleId, roleId);
            List<RoleMenuRef> roleMenuRefList = roleMenuRefService.list(lqw);

            List<HomeMenuTreeResp> homeMenuTreeRespList = buildMenuTree(menus, roleMenuRefList);
            return Message.success(homeMenuTreeRespList);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("首页菜单获取失败");
        }
    }

    @ApiOperation("角色管理-保存菜单")
    @PostMapping(value = "/addRoleMenuTree")
    public Message<Boolean> addRoleMenuTree(@RequestBody RoleMenuTreeReq roleMenuTreeReq) {
        Preconditions.checkArgument(Objects.nonNull(roleMenuTreeReq.getRoleId()), "角色id不能为空");
        try {
            LambdaQueryWrapper<RoleMenuRef> lqw = Wrappers.lambdaQuery();
            lqw.eq(RoleMenuRef::getDelStatus, DelStatusEnum.NORMAL.getCode())
                    .eq(RoleMenuRef::getRoleId, roleMenuTreeReq.getRoleId());
            RoleMenuRef roleMenuRef = new RoleMenuRef()
                    .setDelStatus(DelStatusEnum.ERROR.getCode());
            roleMenuRefService.update(roleMenuRef, lqw);
            if (CollUtil.isEmpty(roleMenuTreeReq.getMenuIdList())) {
                return Message.success(true);
            }
            List<RoleMenuRef> roleMenuRefList = roleMenuTreeReq.getMenuIdList().stream().map(item -> {
                RoleMenuRef rf = new RoleMenuRef()
                        .setRoleId(roleMenuTreeReq.getRoleId())
                        .setDelStatus(DelStatusEnum.NORMAL.getCode())
                        .setMenuId(item);
                return rf;
            }).collect(Collectors.toList());
            roleMenuRefService.saveBatch(roleMenuRefList);
            return Message.success(true);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Message.error("首页菜单获取失败");
        }
    }


    private List<HomeMenuTreeResp> buildMenuTree(List<SysMenuResp> menuList, List<RoleMenuRef> roleMenuRefList) {
        // 使用 LinkedHashMap 的原因，是为了排序 。实际也可以用 Stream API ，就是太丑了。
        Map<Long, HomeMenuTreeResp> treeNodeMap = new LinkedHashMap<>();
        menuList.forEach(menu -> {
            HomeMenuTreeResp homeMenuTreeResp = new HomeMenuTreeResp();
            BeanUtil.copyProperties(menu, homeMenuTreeResp);
            homeMenuTreeResp.setMenuid(menu.getId());
            homeMenuTreeResp.setMenuname(menu.getName());
            homeMenuTreeResp.setUrl(menu.getPath());
            if (CollUtil.isNotEmpty(roleMenuRefList)) {
                long countFlag = roleMenuRefList.stream().filter(f -> f.getMenuId().equals(menu.getId())).count();
                if (countFlag > 0L) {
                    homeMenuTreeResp.setChecked(true).setOpen(true);
                }
            }
            treeNodeMap.put(menu.getId(), homeMenuTreeResp);
        });
        // 处理父子关系
        treeNodeMap.values().forEach(childNode -> {
            if (childNode.getParentId().equals(MenuIdEnum.ROOT.getId())) {
                return;
            }
            // 获得父节点
            HomeMenuTreeResp parentNode = treeNodeMap.get(childNode.getParentId());
            if (Objects.isNull(parentNode)) {
                log.info("[buildRouterTree][resource({}) 找不到父资源({})]", childNode.getMenuid(), childNode.getParentId());
                return;
            }
            // 将自己添加到父节点中
            if (CollUtil.isEmpty(parentNode.getMenus())) {
                parentNode.setMenus(new ArrayList<>());
            }
            childNode.setHasThird("N");
            parentNode.getMenus().add(childNode);
        });
        // 获得到所有的根节点
        return treeNodeMap.values().stream().filter(node -> MenuIdEnum.ROOT.getId().equals(node.getParentId())).collect(Collectors.toList());
    }
}
